package hr.fer.zpr.nmbp.project2.dao;

import hr.fer.zpr.nmbp.project2.dao.exceptions.PrimaryKeyConstraintException;
import hr.fer.zpr.nmbp.project2.model.Bolest;
import hr.fer.zpr.nmbp.project2.model.Dijagnoza;
import hr.fer.zpr.nmbp.project2.model.Karton;
import java.util.ArrayList;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.exception.ConstraintViolationException;

public class DijagnozaDAO {

	private Session session;

    public DijagnozaDAO(Session session) {
        this.session = session;
    }

	public void save(Dijagnoza dijagnoza) {
		if (dijagnoza.getSifra() == null || dijagnoza.getSifra().isEmpty()) {
			throw new PrimaryKeyConstraintException(
					"Šifra dijagnoze ne smije biti NULL");
		}

		Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.saveOrUpdate(dijagnoza);
            
            List<Bolest> bolesti = dijagnoza.getBolesti();
            for (Bolest b : bolesti) {
                if (!b.getDijagnoze().contains(dijagnoza)) {
                    b.getDijagnoze().add(dijagnoza);
                    session.merge(b);
                }
            }
            
            tx.commit();
        } catch (ConstraintViolationException e) {
            if (tx != null) tx.rollback();
            throw new PrimaryKeyConstraintException("Šifra dijagnoze već postoji u bazi podataka");
        } catch (Exception e) {
            e.printStackTrace();
        }
	}

	public void delete(Dijagnoza dijagnoza) {
		Transaction tx = null;
        try {
            tx = session.beginTransaction();
            
            Karton refKarton = dijagnoza.getKarton();
            if (refKarton != null) {
    			refKarton.getDijagnoze().remove(dijagnoza);
                session.merge(refKarton);
        	}
            
            session.delete(dijagnoza);
            tx.commit();
        } catch (Exception e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
            throw new RuntimeException(e);
        }
	}

    /**
     * Gleda sifru i karton.
     * @param dijagnozaPrototype
     * @return 
     */
	public List<Dijagnoza> load(Dijagnoza dijagnozaPrototype) {
		Properties prop = new Properties();
        StringBuilder sb = new StringBuilder();
        sb.append("select d from Dijagnoza as d");
        
        if (dijagnozaPrototype.getSifra() != null) {
            sb.append(" where d.sifra = :sifra");
            prop.setProperty("sifra", dijagnozaPrototype.getSifra());
        }
        
        if (dijagnozaPrototype.getKarton().getPacijentMbo() != null) {
            if (dijagnozaPrototype.getSifra() != null) {
                sb.append(" and");
            } else {
                sb.append(" where");
            }
            sb.append(" d.karton.pacijentMbo = :mbo");
            prop.put("mbo", dijagnozaPrototype.getKarton().getPacijentMbo());
        }
        
        return (List<Dijagnoza>) session.createQuery(sb.toString()).setProperties(prop).list();
	}

	public List<Dijagnoza> loadAll() {
		return (List<Dijagnoza>) session.createQuery("select d from Dijagnoza as d").list();
	}

	public List<Dijagnoza> load(final Date dateFrom, final Date dateTo) {
		Properties prop = new Properties();
        StringBuilder sb = new StringBuilder();
        sb.append("select d from Dijagnoza as d");
        
        if (dateFrom != null) {
            sb.append(" where d.datum >= :dateFrom");
            prop.put("dateFrom", dateFrom);
        }
        if (dateTo != null) {
            if (dateFrom != null) {
                sb.append(" and");
            } else {
                sb.append(" where");
            }
            sb.append(" d.datum <= :dateTo");
            prop.put("dateTo", dateTo);
        }
                                        
        return (List<Dijagnoza>) session.createQuery(sb.toString()).setProperties(prop).list();
	}
	
	public List<Dijagnoza> load(final List<Bolest> bolesti){
		Set<Dijagnoza> dijagnozeSet = new HashSet<Dijagnoza>();
        boolean first = true;
        for (Bolest b : bolesti) {
            if (first) {
                first = false;
                dijagnozeSet.addAll(b.getDijagnoze());
            } else {
                dijagnozeSet.retainAll(b.getDijagnoze());
            }
        }
		
		return new ArrayList<Dijagnoza>(dijagnozeSet);
	}
}
